#include <stdio.h>
#include <string>
#include <vector>
#include <time.h>

#include "protocol.h"
#include "LocalClient.h"
#include "SDL.h"
#include "SDL_image.h"
#include "SDL_ttf.h"

#include "WiiTextArea.h"
#include "OnScreenKeyboard.h"

#ifdef LINUX
#include <pthread.h>
#endif

#include <iostream>

#define NUM_THREADS 3

LocalClient* myClient;
Protocol* proto;
bool do_check_mail = true;
bool do_update = true;
char* nxt_msg="";

WiiTextArea* userListTextArea;
WiiTextArea* messageTextArea;
WiiTextArea* nextMessageTextArea;

SDL_Surface* bg_surface;
SDL_Surface* screen;

void mssleep(unsigned int mseconds)
{
   clock_t goal = mseconds+clock();
   while (goal > clock());
}


pthread_mutex_t mutexproto;
pthread_mutex_t mutexcheck;
pthread_mutex_t mutexgui;

void RenderMainScreen()
{
   #ifdef LINUX
   SDL_Rect zoom_loc;
   SDL_FillRect(SDL_GetVideoSurface(), NULL, 0);

   pthread_mutex_lock (&mutexgui);
   SDL_BlitSurface(bg_surface, 0, screen, 0);
   userListTextArea->Draw();
   messageTextArea->Draw();
   nextMessageTextArea->Draw();
   SDL_Flip(screen);
   do_update = false;
   pthread_mutex_unlock (&mutexgui);
   #endif
}

void *NetReceive(void *threadid)
{
   int tid;
   tid = (int)threadid;
   int my_uid;

   pthread_mutex_lock (&mutexcheck);
   while(do_check_mail)
   {
      pthread_mutex_unlock (&mutexcheck);
      mssleep(5000);
      pthread_mutex_lock (&mutexproto);
      switch(proto->Rcv_Handler())
      {
         case MessageType::UID_RESPONSE:
            if((my_uid = proto->ParseUid(proto->Get_Rcv_Buffer())) != -1)
            {
               myClient->Set_Uid(my_uid);
            }
            else printf("Failed (Invalid Uid Returned [%d]).\n",my_uid);
           // printf("UID Rcvd (%d).\n",my_uid);
            break;
         case MessageType::MAIL_RESPONSE:
            messageTextArea->Append(proto->ParseMessages(proto->Get_Rcv_Buffer()));
            pthread_mutex_lock (&mutexgui);
            do_update = true;
            pthread_mutex_unlock (&mutexgui);
            proto->Clear_Rcv_Buffer();
          //  printf("Mail Response.\n");
            break;
         case MessageType::USER_LIST_RESPONSE:
            userListTextArea->Clear();
            userListTextArea->Append(proto->ParseUsers(proto->Get_Rcv_Buffer()));
            pthread_mutex_lock (&mutexgui);
            do_update = true;
            pthread_mutex_unlock (&mutexgui);
            proto->Clear_Rcv_Buffer();
            //printf("User List Response.\n");
            break;
         case MessageType::ALL_DATA_RESPONSE:
            printf("All Data Response.\n");
            break;
         case MessageType::NONE:
            proto->Clear_Rcv_Buffer();
            break;
         default:
            break;
      }
      pthread_mutex_unlock (&mutexproto);
      pthread_mutex_lock (&mutexcheck);
   }
   pthread_mutex_unlock (&mutexcheck);
}

void *CheckMail(void *threadid)
{
   int tid;
   tid = (int)threadid;
   
   pthread_mutex_lock (&mutexcheck);
   while(do_check_mail)
   {
      pthread_mutex_unlock (&mutexcheck);
      mssleep(300000);
      printf("CheckMail Check...\n");
      pthread_mutex_lock (&mutexproto);
      proto->Rqst_Mail();
      pthread_mutex_unlock (&mutexproto);
      pthread_mutex_lock (&mutexcheck);
   }
   pthread_mutex_unlock (&mutexcheck);
}

void *UpdateUserList(void *threadid)
{
   int tid;
   tid = (int)threadid;

   pthread_mutex_lock (&mutexcheck);
   while(do_check_mail)
   {
      pthread_mutex_unlock (&mutexcheck);
      mssleep(1000000);
    //  printf("Update User List Check...\n");
      pthread_mutex_lock (&mutexproto);
      proto->Rqst_User_List();
      pthread_mutex_unlock (&mutexproto);
      pthread_mutex_lock (&mutexcheck);
   }
   pthread_mutex_unlock (&mutexcheck);

}

int main(int argc, char*argv[]) {

   int received = 0;
   int my_uid = -1;
   bool done = false;
   pthread_t threads[NUM_THREADS];
   int rc, t;
   std::string line;

   bg_surface  = IMG_Load("img/bg.png");

   TTF_Font* font;
   SDL_Color color;
   color.r = 0x72;
   color.g = 0xbf;
   color.b = 0xe9;
   
   if (argc != 4) {
      fprintf(stderr, "Useage: %s <server_ip> <port> <username>\n",argv[0]);
      exit(1);
   }

   OnScreenKeyboard* osk;
   if(SDL_Init(SDL_INIT_VIDEO)==-1)
   {
      printf("failed to init video: (%s)",SDL_GetError());
      return 1;
   }
   TTF_Init();

   screen = SDL_SetVideoMode(640, 480, 24, SDL_ANYFORMAT);
   font = TTF_OpenFont("font/wiifont.ttf",14);
   if(font == NULL){ printf("Error loading font! (%s)",SDL_GetError()); return 0;}

   osk = new OnScreenKeyboard(screen, "config/key_config.xml");

   userListTextArea    = new WiiTextArea(screen, font, color, 483, 44, 10, 15, 14);
   messageTextArea     = new WiiTextArea(screen, font, color, 26, 256, 11, 120, 14);
   nextMessageTextArea = new WiiTextArea(screen, font, color, 18, 436, 1, 100, 14);

   proto = new Protocol();
   myClient = new LocalClient(-1,argv[3],0,0,0);
   
   messageTextArea->Append("Connecting....\n");
   RenderMainScreen();

   if(!(proto->Connect(argv[1],atoi(argv[2])))){
      fprintf(stderr, "Failed to connect.");
      exit(1);
   }
   RenderMainScreen();

   messageTextArea->Append("Connected.\n");
   RenderMainScreen();

   messageTextArea->Append("Getting Uid...\n");
   RenderMainScreen();
   proto->Get_Uid();
   
   messageTextArea->Append("Updating Name...");
   RenderMainScreen();
   if(proto->Update_Name(myClient->Get_Name())) messageTextArea->Append("Success.\n");
   else messageTextArea->Append("Failed.\n");

   messageTextArea->Append("Updating Pos...");
   RenderMainScreen();

   if(proto->Update_Pos(myClient->X(),myClient->Y(),myClient->Z())) messageTextArea->Append("Success.\n");
   else messageTextArea->Append("Failed.\n");

 //  messageTextArea->Append("Requesting User List...\n");

   RenderMainScreen();
   if(proto->Rqst_User_List()) printf("Success.\n");
   else printf("Failed.\n");

    rc = pthread_create(&threads[0], NULL, NetReceive, (void *)t);
    if(rc) {
      printf("ERROR; return code from pthread_create() is %d\n", rc);
      exit(-1);
   }

   rc = pthread_create(&threads[1], NULL, CheckMail, (void *)t);
   if(rc) {
      printf("ERROR; return code from pthread_create() is %d\n", rc);
      exit(-1);
   }

    rc = pthread_create(&threads[2], NULL, UpdateUserList, (void *)t);
    if(rc) {
      printf("ERROR; return code from pthread_create() is %d\n", rc);
      exit(-1);
   }
   
   #ifdef LINUX
   SDL_Event event;
   
   while(!done && SDL_WaitEvent(&event)!=-1)
   {
      int t_x = event.button.x;
      int t_y = event.button.y;
      switch(event.type)
      {
         case SDL_MOUSEBUTTONDOWN:
            if(t_x > 10 && t_x < 200 && t_y > 35 && t_y < 200)
            {
               if(t_y > 35 && t_y < 75)
               {
                  //button 1 pressed (Change_name)
                  char* tname = osk->EditString(myClient->Get_Name());
                  if(tname != NULL) 
                  {
                         myClient->Update_Name(tname);
                         RenderMainScreen();
			 pthread_mutex_lock (&mutexproto);
			 proto->Update_Name(tname);
			 pthread_mutex_unlock (&mutexproto);
                  }
               }
               else if(t_y > 78 && t_y < 116)
               {
                  //button 2 pressed
               }
               else if(t_y > 120 && t_y < 158)
               {
                  //button 3 (About) pressed
               }
               else if(t_y > 161 && t_y < 200)
               {
                  //button 4 (Quit) pressed
		 pthread_mutex_lock (&mutexcheck);
		 do_check_mail = false;
		 pthread_mutex_unlock (&mutexcheck);
		 sleep(2);
		 pthread_mutex_lock (&mutexproto);
		 proto->Send_Quit();
		 pthread_mutex_unlock (&mutexproto);
		 pthread_exit(NULL);
		 done = true;
               }
            }
            else if(t_x > 15 && t_x < 547 && t_y > 431 && t_y < 465)
            {
                //clicked edit box
                nxt_msg = osk->EditString(nxt_msg);
                nextMessageTextArea->Clear();
                nextMessageTextArea->Append(nxt_msg);
                RenderMainScreen();
            }
            else if(t_x > 555 && t_x < 626 && t_y > 431 && t_y < 465)
            {
                //msg send
		 pthread_mutex_lock (&mutexproto);
		 proto->Send_Message(nxt_msg,"global");
                 nxt_msg = "\0";
		 pthread_mutex_unlock (&mutexproto);

                 nextMessageTextArea->Clear();
		 RenderMainScreen();
            }
                   
            break;
         case SDL_MOUSEMOTION:
            //pos_x = event.button.x;
            //pos_y = event.button.y;
            //DrawKeyboard();
            break;
      }

      pthread_mutex_lock (&mutexgui);
      if(do_update){ 
         pthread_mutex_unlock (&mutexgui); 
         RenderMainScreen();
      }else {
         pthread_mutex_unlock (&mutexgui); 
      }
	
   }   
   #endif

   proto->Disconnect();

   if(proto != NULL) delete proto;
   proto = NULL;

   exit(0);
}

